﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using LitJson;
using System.Text.RegularExpressions;

public class MapLevel : MonoBehaviour {
  public static MapLevel Instance { get; private set; }
  private void Awake() {
    Instance = this;
  }

  /*
    * 空白 XX
    * 砖块 brick  B<n>
    * 钢块 steel  T<n>
    * 河流 river  R
    * 雪地 snow   S
    * 森林 forest F
    * 老鹰 eagle  E
  */
  public struct Map {
    public List<Vector2Int> bricks;
    public List<Vector2Int> steels;
    public List<int> rivers;
    public List<int> snows;
    public List<int> forests;
    public int eagle;
  };
  public struct Bot {
    public int basic;
    public int fast;
    public int power;
    public int armor;
  };
  public struct Data {
    public string name;
    public int difficulty;
    public Bot bot;
    public Map map;
  };

  public Data mapData { get; private set; }
  public GameObject brickPrefab;
  public GameObject steelPrefab;
  public GameObject riverPrefab;
  public GameObject snowPrefab;
  public GameObject forestPrefab;
  public GameObject eaglePrefab;

  public bool LoadLevel(int level) {
    TextAsset jsonText = Resources.Load<TextAsset>("Level/stage" + level);
    if (!jsonText) return false;
    return LoadLevel(jsonText.text);
  }
  public bool LoadLevel(string jsonStageText) {
    Data data = new Data();
    JsonData jData = JsonMapper.ToObject(jsonStageText);
    if (jData == null) return false;

    // parse name and difficulty
    data.name = (string)jData["name"];
    data.difficulty = (int)jData["difficulty"];

    // parse bot
    data.bot = new Bot();
    data.bot.basic = (int)jData["bot"]["basic"];
    data.bot.fast = (int)jData["bot"]["fast"];
    data.bot.power = (int)jData["bot"]["power"];
    data.bot.armor = (int)jData["bot"]["armor"];

    // parse map
    data.map = new Map();
    data.map.bricks = new List<Vector2Int>();
    data.map.steels = new List<Vector2Int>();
    data.map.rivers = new List<int>();
    data.map.snows = new List<int>();
    data.map.forests = new List<int>();
    JsonData jMap = jData["map"];
    for (int row = 0; row < Config.mapHeight; ++row) {
      string[] line = Regex.Split(((string)jMap[row]).ToLower(), "\\ +");
      for (int col = 0; col < Config.mapWidth; ++col) {
        string item = line[col].Trim();
        int idx = row * Config.mapHeight + col;
        if (item[0] == 'b') {
          Vector2Int v2 = new Vector2Int();
          v2.x = idx;
          v2.y = System.Convert.ToInt16(item.Substring(1), 16);
          data.map.bricks.Add(v2);
        } else if (item[0] == 't') {
          Vector2Int v2 = new Vector2Int();
          v2.x = idx;
          v2.y = System.Convert.ToInt16(item.Substring(1), 16);
          data.map.steels.Add(v2);
        } else if (item[0] == 'r') {
          data.map.rivers.Add(idx);
        } else if (item[0] == 'f') {
          data.map.forests.Add(idx);
        } else if (item[0] == 's') {
          data.map.snows.Add(idx);
        } else if (item[0] == 'e') {
          data.map.eagle = idx;
        } else if (item[0] == 'x') {
        }
      }
    }

    mapData = data;
    return true;
  }
  public bool InitMap() {
    // destroy all child objs
    for (int i = transform.childCount - 1; i >= 0; --i)
      Destroy(transform.GetChild(i).gameObject);

    // brick
    foreach (Vector2Int d in mapData.map.bricks)
      CreateMapItem(brickPrefab, d.x);
    // steel
    foreach (Vector2Int d in mapData.map.steels)
      CreateMapItem(steelPrefab, d.x);
    // river
    foreach (int idx in mapData.map.rivers)
      CreateMapItem(riverPrefab, idx);
    // snow
    foreach (int idx in mapData.map.snows)
      CreateMapItem(snowPrefab, idx);
    // forest
    foreach (int idx in mapData.map.forests)
      CreateMapItem(forestPrefab, idx);
    // eagle
    CreateMapItem(eaglePrefab, mapData.map.eagle);
    return true;
  }

  public void DumpMapData() {
    Data data = mapData;
    string msg = "base:n" + data.name + "|d" + data.difficulty + "\n";
    msg += "bot:b" + data.bot.basic + "|f" + data.bot.fast + "|p" + data.bot.power + "|a" + data.bot.armor + "\n";
    msg += "map:b" + data.map.bricks.Count + "|s" + data.map.steels.Count + "|r" + data.map.rivers.Count;
    msg += "|s" + data.map.snows.Count + "|f" + data.map.forests.Count + "\n";
    for (int row = 0; row < Config.mapHeight; ++row) {
      msg += "  ";
      for (int col = 0; col < Config.mapWidth; ++col) {
        int idx = row * Config.mapHeight + col;
        if (data.map.eagle == idx) msg += "EX";
        else if (data.map.forests.Exists(s => { return s == idx; })) msg += "FX";
        else if (data.map.snows.Exists(s => { return s == idx; })) msg += "SX";
        else if (data.map.rivers.Exists(s => { return s == idx; })) msg += "RX";
        else if (data.map.steels.Exists(s => { return s.x == idx; })) {
          Vector2Int d = data.map.steels.Find(s => { return s.x == idx; });
          msg += "T" + System.Convert.ToString(d.y, 16).ToUpper();
        } else if (data.map.bricks.Exists(s => { return s.x == idx; })) {
          Vector2Int d = data.map.bricks.Find(s => { return s.x == idx; });
          msg += "B" + System.Convert.ToString(d.y, 16).ToUpper();
        } else {
          msg += "XX";
        }
        msg += " ";
      }
      msg += "\n";
    }
    Debug.Log(msg);
  }

  // create a map tile
  protected void CreateMapItem(GameObject prefab, int idx) {
    int row = idx / Config.mapHeight;
    int col = idx % Config.mapWidth;
    Vector3 position = Vector3.zero;
    position.x = col - 6;
    position.y = 6 - row;
    GameObject obj = Instantiate(prefab, position, Quaternion.identity);
    obj.transform.SetParent(gameObject.transform);
  }
}
